import serial
import time

class SpcSerial:
    def __init__(self, name="serialX", port="COM3", baudrate=115200, timeout=1):
        self.name = name
        self.port = port
        self.baudrate = baudrate
        self.timeout = timeout
        self.serial = None
        print(f"Initialized {self.name} on {self.port} with baud rate {self.baudrate}")

    def __enter__(self):
        self.Open()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.Close()

    def Open(self):
        if self.serial is None or not self.serial.isOpen():
            self.serial = serial.Serial(self.port, self.baudrate, timeout=self.timeout)
            print(f"'{self.name} {self.port}' is now open.")

    def IsOpened(self):
        return self.serial is not None and self.serial.isOpen()

    def Close(self):
        if self.serial is not None and self.serial.isOpen():
            self.serial.close()
            print(f"'{self.name} {self.port}' is now closed.")

    def Send(self, data=b"__?__"):
        if not self.serial.isOpen():
            raise ValueError("Serial port is not open.")
        self.serial.write(data)

    def ReadLine(self) -> bytes:
        if not self.serial.isOpen():
            raise ValueError("Serial port is not open.")
        return self.serial.readline()

    def Read(self, length: int) -> bytes:
        if not self.serial.isOpen():
            raise ValueError("Serial port is not open.")
        return self.serial.read(length)

    def ReadByte2Str(self, length: int, encoding='utf-8'):
        if not self.serial.isOpen():
            raise ValueError("Serial port is not open.")
        return self.serial.read(length).decode(encoding)

    def ReadStrList(self, lines: int, encoding='utf-8', eol=b'\n') -> list[str]:
        if not self.serial.isOpen():
            raise ValueError("Serial port is not open.")
        ret_list = []
        while len(ret_list) < lines:
            try:
                data = self.serial.read_until(eol).decode(encoding)
            except UnicodeDecodeError:
                if encoding == 'utf-8':
                    data = self.serial.read_until(eol).decode('gbk')  # Fallback encoding
                else:
                    data = self.serial.read_until(eol).decode('utf-8')  # Fallback encoding

            except serial.SerialException as e:
                print(f"Serial error: {e}")
                break
            if data:
                ret_list.append(data)
            else:
                break
        return ret_list

# Example usage
if __name__ == '__main__':
    with SpcSerial(name="alog", port="COM49", baudrate=115200) as uart_alog:
        try:
            while True:
                data_dev = uart_alog.ReadLine()
                if data_dev:
                    uart_alog.Send(data_dev)
                    print(f"Sent: {data_dev}")
                time.sleep(0.01)
        except KeyboardInterrupt:
            print("Program terminated by user.")